package com.nulldev.util.threading.v3;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.nulldev.util.java.JVMUtil;
import com.nulldev.util.math.MathUtil;
import com.nulldev.util.threading.fastES.LtqExecutor;
import com.nulldev.util.threading.v3_extensions.Task;
import com.nulldev.util.threading.v3_extensions.TaskStatus;

public class ThreadDispatcher {
	public static int randomID() {
		return MathUtil.randInt(Integer.MIN_VALUE, Integer.MAX_VALUE);
	}
	
	private static ThreadDispatcher threadDispatcher;
    private final ExecutorService executorService;
    public ThreadsMonitor threadsMonitor = ThreadsMonitor.instance();

    public ThreadDispatcher() {
    	this(false);
    }
    
    public ThreadDispatcher(final boolean preferLTQ) {
       if (!preferLTQ) {
    	   this.executorService = Executors.newCachedThreadPool();
       }else {
    	   this.executorService = new LtqExecutor();
       }
    }
    
    public ThreadDispatcher(final ExecutorService serv) {
    	this.executorService = serv;
    }

    public static ThreadDispatcher instance() {
        if (threadDispatcher == null)
            threadDispatcher = new ThreadDispatcher(!JVMUtil.isArg("--threadit3.disableLTQ"));
        return threadDispatcher;
    }

    public void addTask(final IWorker task) {
        this.executorService.submit(task);
        this.threadsMonitor.addIWorker(task);
    }
    
    public void addTask(final Task task) {
    	this.addTask(task, "$ThreadDispatcher.v3_1.Task");
    }
    
    public void addTask(final Task task, final String name) {
    	final IWorker conv = new IWorker() {
			
			@Override
			public void run() {
				task.execute();
			}
			
			@Override
			public void shutdown() {
				task.kill();
			}
			
			@Override
			public boolean isAlive() {
				return task.status() == TaskStatus.RUNNING;
			}
			
			@Override
			public String getName() {
				return name;
			}
			
			@Override
			public int getID() {
				return randomID();
			}
		};
		this.addTask(conv);
    }
    
    public <T> Future<T> addFutureTask(final IWorker task) {
    	return (Future<T>) this.executorService.submit(new Runnable() {
			
			@Override
			public void run() {
				task.run();
			}
		});
    }
    
    public ExecutorService getExec() {
    	return this.executorService;
    }
}
